# -*- coding: utf-8 -*-

"""剑指 Offer II 093. 最长斐波那契数列
如果序列 X_1, X_2, ..., X_n 满足下列条件，就说它是 斐波那契式 的：
n >= 3
对于所有 i + 2 <= n，都有 X_i + X_{i+1} = X_{i+2}
给定一个严格递增的正整数数组形成序列 arr ，找到 arr 中最长的斐波那契式的子序列的长度。如果一个不存在，返回  0 。
（回想一下，子序列是从原序列  arr 中派生出来的，它从 arr 中删掉任意数量的元素（也可以不删），而不改变其余元素的顺序。例如， [3, 5, 8] 是 [3, 4, 5, 6, 7, 8] 的一个子序列）

示例 1：
输入: arr = [1,2,3,4,5,6,7,8]
输出: 5
解释: 最长的斐波那契式子序列为 [1,2,3,5,8] 。

示例 2：
输入: arr = [1,3,7,11,12,14,18]
输出: 3
解释: 最长的斐波那契式子序列有 [1,11,12]、[3,11,14] 以及 [7,11,18] 。

提示：
3 <= arr.length <= 1000
1 <= arr[i] < arr[i + 1] <= 10^9"""

class Solution:
    """开始没有思路，想用一种数据结构来表示前i位的所有斐波那契序列，树不行，图也不行。
    想用动态规划来解决，但是实在找不到与第i位的关系。
    再分析，Fibonacci 是 a+b=c 的关系，c 与前面可以组成关系的 a,b 两位有关系。
    这时候用回溯法先理一下步骤，可以假设从第 i-1 位提供一个 a,b 探头（有可能该探头是Fibonacci m,a,b 的头），
        进入第i回时，可以根据 a+b vs c 的关系来形成新的探头组合，或者新的Fibonacci，同时将终结的Fibonacci收集，更新最长Fibonacci长度
    
    如果用动态规划的方法，进入第 i 位时，需要有所有探头组合，再进入第 i+1 位，更新探头组合，其实更回溯差不多，逻辑上回溯可以通过剪枝达到相同的效果
    如果 a+b == c 存在 f(c,b) = f(b,a)+1
    
    动态规划，备忘录自始至终是一个，处于动态更新中，可以不用递归，直接用循环。定义 dp[i][j] = k, 以(i, j)为探头的Fibonacci长度为k"""
    def lenLongestFibSubseq(self, arr) -> int:
        table = dict((v, l) for l, v in enumerate(arr))
        dp = [[2 for _ in range(0, len(arr))] for _ in range(0, len(arr)-1)]
        longest = 2
        for i in range(1, len(arr)):
            ni = arr[i]
            for j in range(i):
                nj = arr[j]
                if ni-nj in table and (k:=table[ni-nj]) < j:
                    # arr[k]+arr[j] = arr[i]
                    k = table[ni-nj]
                    dp[j][i] = dp[k][j] + 1
                longest = max(dp[j][i], longest)
        return  longest if longest > 2 else 0


if __name__ == '__main__':
    so = Solution()
    print(so.lenLongestFibSubseq([1,2,3,4,5,6,7,8]))
    print(so.lenLongestFibSubseq([1,3,7,11,12,14,18]))

